#include <stdio.h>
#include "du_websocket_client.h"

#define NO_DATA_TIMEOUT_SEC 20

static const char *TAG = "websocket";

#define WS_URI "ws://192.168.5.249:8000"

static TimerHandle_t shutdown_signal_timer;
static SemaphoreHandle_t shutdown_sema;
static esp_websocket_client_handle_t client;
static void log_error_if_nonzero(const char *message, int error_code)
{
    if (error_code != 0)
    {
        ESP_LOGE(TAG, "Last error %s: 0x%x", message, error_code);
    }
}

static void shutdown_signaler(TimerHandle_t xTimer)
{
    ESP_LOGI(TAG, "No data received for %d seconds, signaling shutdown", NO_DATA_TIMEOUT_SEC);
    xSemaphoreGive(shutdown_sema);
}

static void websocket_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{
    esp_websocket_event_data_t *data = (esp_websocket_event_data_t *)event_data;
    switch (event_id)
    {
    case WEBSOCKET_EVENT_CONNECTED:
        ESP_LOGI(TAG, "WEBSOCKET_EVENT_CONNECTED");
        break;
    case WEBSOCKET_EVENT_DISCONNECTED:
        ESP_LOGI(TAG, "WEBSOCKET_EVENT_DISCONNECTED");
        log_error_if_nonzero("HTTP status code", data->error_handle.esp_ws_handshake_status_code);
        if (data->error_handle.error_type == WEBSOCKET_ERROR_TYPE_TCP_TRANSPORT)
        {
            log_error_if_nonzero("reported from esp-tls", data->error_handle.esp_tls_last_esp_err);
            log_error_if_nonzero("reported from tls stack", data->error_handle.esp_tls_stack_err);
            log_error_if_nonzero("captured as transport's socket errno", data->error_handle.esp_transport_sock_errno);
        }
        break;
        case WEBSOCKET_EVENT_DATA:
            ESP_LOGI(TAG, "WEBSOCKET_EVENT_DATA");

            cJSON *root = cJSON_Parse(data->data_ptr);
            if (root == NULL)
            {
                ESP_LOGE(TAG, "Failed to parse JSON: %s", cJSON_GetErrorPtr());
                break;
            }

            cJSON *id = cJSON_GetObjectItem(root, "spark_data");
            if (id != NULL && cJSON_IsString(id))
            {
                ESP_LOGW(TAG, "Json={'id': '%s'}", id->valuestring);
            }
            else
            {
                ESP_LOGE(TAG, "Failed to get 'spark_data' from JSON");
            }

            cJSON_Delete(root);

            xTimerReset(shutdown_signal_timer, portMAX_DELAY);
            break;
    // case WEBSOCKET_EVENT_DATA:
    //     ESP_LOGI(TAG, "WEBSOCKET_EVENT_DATA");

    //     FILE *f = fopen("/spiffs/recorded_audio.pcm", "wb");
    //     if (f == NULL)
    //     {
    //         ESP_LOGE(TAG, "Failed to open file for writing");
    //         break;
    //     }

    //     // Write binary data to the file
    //     size_t bytes_written = fwrite(data->data_ptr, 1, data->data_len, f);
    //     if (bytes_written != data->data_len)
    //     {
    //         ESP_LOGE(TAG, "Failed to write entire data to file");
    //         fclose(f);
    //         break;
    //     }

    //     // Close the file
    //     fclose(f);
    //     ESP_LOGI(TAG, "Binary data saved to file");

    //     // Optionally, reset a timer
    //     xTimerReset(shutdown_signal_timer, portMAX_DELAY);
    //     break;

    case WEBSOCKET_EVENT_ERROR:
        ESP_LOGI(TAG, "WEBSOCKET_EVENT_ERROR");
        log_error_if_nonzero("HTTP status code", data->error_handle.esp_ws_handshake_status_code);
        if (data->error_handle.error_type == WEBSOCKET_ERROR_TYPE_TCP_TRANSPORT)
        {
            log_error_if_nonzero("reported from esp-tls", data->error_handle.esp_tls_last_esp_err);
            log_error_if_nonzero("reported from tls stack", data->error_handle.esp_tls_stack_err);
            log_error_if_nonzero("captured as transport's socket errno", data->error_handle.esp_transport_sock_errno);
        }
        break;
    }
}

void websocket_app_start_init(void)
{

    // 创建定时器和信号量
    shutdown_signal_timer = xTimerCreate("Websocket shutdown timer", NO_DATA_TIMEOUT_SEC * 1000 / portTICK_PERIOD_MS,
                                         pdFALSE, NULL, shutdown_signaler);
    shutdown_sema = xSemaphoreCreateBinary();

}

void websocket_app_start_chat(void)
{
    esp_websocket_client_config_t websocket_cfg = {};

    // 填充 WebSocket 配置
    websocket_cfg.uri = WS_URI "/chat";
    websocket_cfg.skip_cert_common_name_check = true;

    ESP_LOGI(TAG, "Connecting to %s...", websocket_cfg.uri);

    // 初始化 WebSocket 客户端
    client = esp_websocket_client_init(&websocket_cfg);
    if (client == NULL)
    {
        ESP_LOGE(TAG, "Failed to initialize WebSocket client");
        return;
    }

    // 注册 WebSocket 事件处理函数
    esp_websocket_register_events(client, WEBSOCKET_EVENT_ANY, websocket_event_handler, (void *)client);

    // 启动 WebSocket 客户端
    esp_websocket_client_start(client);

    char *message = "写一个四句诗词 描写夏天的炎热";
    int length = strlen(message); // 获取字符串实际长度，不包括结尾的空字符 '\0'
    esp_websocket_client_send_text(client, message, length, portMAX_DELAY);
    // du_ws_send(message, data_type, sizeof(message));
    // 启动定时器
    xTimerStart(shutdown_signal_timer, portMAX_DELAY);

    // 等待信号量释放，这里要确保信号量在适当的时候释放
    xSemaphoreTake(shutdown_sema, portMAX_DELAY);

    // 关闭 WebSocket 客户端
    esp_websocket_client_close(client, portMAX_DELAY);
    ESP_LOGI(TAG, "Websocket Stopped");

    // 销毁 WebSocket 客户端
    esp_websocket_client_destroy(client);
}

void websocket_app_start_tts(void)
{
    esp_websocket_client_config_t websocket_cfg = {};


    // 填充 WebSocket 配置
    websocket_cfg.uri = WS_URI "/tts";
    websocket_cfg.skip_cert_common_name_check = true;

    ESP_LOGI(TAG, "Connecting to %s...", websocket_cfg.uri);

    // 初始化 WebSocket 客户端
    client = esp_websocket_client_init(&websocket_cfg);
    if (client == NULL)
    {
        ESP_LOGE(TAG, "Failed to initialize WebSocket client");
        return;
    }

    // 注册 WebSocket 事件处理函数
    esp_websocket_register_events(client, WEBSOCKET_EVENT_ANY, websocket_event_handler, (void *)client);

    // 启动 WebSocket 客户端
    esp_websocket_client_start(client);

    char *message = "写一个四句诗词 描写夏天的炎热";
    int length = strlen(message); // 获取字符串实际长度，不包括结尾的空字符 '\0'
    esp_websocket_client_send_text(client, message, length, portMAX_DELAY);
    // du_ws_send(message, data_type, sizeof(message));
    // 启动定时器
    xTimerStart(shutdown_signal_timer, portMAX_DELAY);

    // 等待信号量释放，这里要确保信号量在适当的时候释放
    xSemaphoreTake(shutdown_sema, portMAX_DELAY);

    // 关闭 WebSocket 客户端
    esp_websocket_client_close(client, portMAX_DELAY);
    ESP_LOGI(TAG, "Websocket Stopped");

    // 销毁 WebSocket 客户端
    esp_websocket_client_destroy(client);
}


#define FILE_PATH "/spiffs/demo.pcm"  // SPIFFS 中文件的路径
#define MAX_DATA_SIZE 1024  // 根据你的需求设置合适的数据大小
void websocket_app_start_stt(void)
{
    esp_websocket_client_config_t websocket_cfg = {};

    // 填充 WebSocket 配置
    websocket_cfg.uri = WS_URI "/stt";
    websocket_cfg.skip_cert_common_name_check = true;

    ESP_LOGI(TAG, "Connecting to %s...", websocket_cfg.uri);

    // 初始化 WebSocket 客户端
    client = esp_websocket_client_init(&websocket_cfg);
    if (client == NULL)
    {
        ESP_LOGE(TAG, "Failed to initialize WebSocket client");
        return;
    }

    // 注册 WebSocket 事件处理函数
    esp_websocket_register_events(client, WEBSOCKET_EVENT_ANY, websocket_event_handler, (void *)client);

    // 启动 WebSocket 客户端
    esp_websocket_client_start(client);

    // 打开 SPIFFS 文件进行读取
    FILE* file = fopen(FILE_PATH, "rb");
    if (file == NULL) {
        ESP_LOGE(TAG, "Failed to open file for reading");
        esp_websocket_client_destroy(client);
        return;
    }

    // 读取文件内容并发送
    char buffer[MAX_DATA_SIZE];
    size_t bytes_read;
    while ((bytes_read = fread(buffer, 1, MAX_DATA_SIZE, file)) > 0) {
        // 发送二进制数据
        esp_websocket_client_send_bin(client, buffer, bytes_read, portMAX_DELAY);
    }

    // 关闭文件
    fclose(file);

    // 发送完成后的操作（可以根据需要进行调整）
    xTimerStart(shutdown_signal_timer, portMAX_DELAY);
    xSemaphoreTake(shutdown_sema, portMAX_DELAY);

    // 关闭 WebSocket 客户端
    esp_websocket_client_close(client, portMAX_DELAY);
    ESP_LOGI(TAG, "Websocket Stopped");

    // 销毁 WebSocket 客户端
    esp_websocket_client_destroy(client);
}
